﻿//===============================================================================
//	LuaManager.h
//	C++ -> LUA接口管理器
//  C++调用LUA脚本的入口，含各种安全机制、Lua栈、据参数调用对应脚本等
//===============================================================================

#pragma once

#include <cstdint>
#include <memory>
#include <mutex>
#include <atomic>
#include "../../3rd/lua_5.1/src/lua.hpp"
#include "../../3rd/libjson/json.h"

#define LUA_ERROR_MESSAGE  ((char*)lua_tostring(m_state, -1))


//-------------------------------------------------------------------------------
extern "C" {
	typedef int (*LuaFunctionType)(struct lua_State *ls);
};

//-------------------------------------------------------------------------------
class LuaManager
{
	static const int32_t s_max_stack_step = 64;
	static const int32_t LUA_OK = 0;
	static const bool static_Record_Script_Step = false;
	static const bool static_Reload_Script = false;
	static const uint32_t size_256 = 256;
	static const int32_t invalid_int32_value = -1;
 

	//---------------------------------------------------------------------------

	enum 
	{
		ScriptCreateError,
		ScriptStateIsNullptr,
		ScriptLenError,
		ScriptCompileError,
		ScriptRunError,
		ScriptErrorNotNumber,
		ScriptErrorNotString,
	};

	//---------------------------------------------------------------------------
	class StackStep
	{
	public:
		StackStep(void);
		~StackStep(void);

	public:
		void Reset(void);

	public:
		int32_t m_script_id;
		char	m_function_name[size_256];
	};

	//---------------------------------------------------------------------------
	class LuaStack
	{
	public:
		LuaStack(void);
		~LuaStack(void);

	public:
		int32_t GetCurrentStepCount(void);

	public:
		void Reset(void);
		bool StepStart(const char* functionName, int32_t scriptId);
		bool StepEnd(void);
		void DisplayStack(void);

	private:
		int32_t m_current_step;
		StackStep m_step[s_max_stack_step];
	};

	//---------------------------------------------------------------------------
public:
	//static LuaManager& GetInstance(void);
	LuaManager();
	~LuaManager(void);

public:
	bool Initialize(void);
	bool Exit(void);

	bool RegisterFunction(char* function_name, LuaFunctionType function);	
	bool LoadScript(const char *file_name);

	bool TryLock(void);

public:
	int32_t CheckResult(int32_t retCode);
	bool	CheckParamCount(int32_t count, const char* functionName);

	bool ReloadScript(int32_t scriptId);

public:
	bool IsNumber(int32_t idx, const char* functionName);
	bool IsString(int32_t idx, const char* functionName);

public:
	//void StartStep(int32_t idx, int32_t scriptId, const char* functionName);
	//void EndStep(int32_t idx, int32_t scriptId, const char* functionName);
	void StartStep(int32_t scriptId, const char* functionName);
	void EndStep(int32_t scriptId, const char* functionName);

public:
	void PushString(const char *val);
	void PushNumber(double val);
	void PushInteger(int32_t val);

	const char *GetStringArgument(int32_t num, const char *val = nullptr);
	double GetNumberArgument(int32_t num, double def = 0.0);
	int32_t GetIntegerArgument(int32_t num, int32_t def = 0);

	void SetIndex(uint32_t _val);


public:
	//根据参数数量相应准备lua运行脚本，0参数、1参数、2参数、3参数、4参数、5、6等
	// none
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName);//idx:playeridx in manager

	int32_t RunScriptFunctionString( int32_t scriptID, const char* functionName, Json::Value jsonValue  );

	// 1
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, const char* argv1);
	std::string RunScriptFunctionStringRet(int32_t scriptID, const char* functionName, const char* argv1);

	// 2
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, uint32_t argv1, uint32_t argv2);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, uint32_t argv1, int32_t argv2);
	int32_t RunScriptFunction ( int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2 );
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, double argv2);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, double argv1, double argv2);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, const char* argv2);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, const char*  argv1, const char* argv2);

	// 3
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, const char * argv3);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, double argv2, const char* argv3);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, const char* argv2, const char* argv3);

	// 4
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, double argv1, double argv2, double argv3, double argv4);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, const char* argv4);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, const char* argv3, const char* argv4);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, const char* argv2, const char* argv3, const char* argv4);

	// 5
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, uint32_t argv1, uint32_t argv2, uint32_t argv3, uint32_t argv4, uint32_t argv5);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, double argv2, double argv3, double argv4, double argv5);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4, const char* argv5);
//	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, double argv4, const char* argv5);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, const char* argv3, const char* argv4, uint32_t argv5);
//	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, const char* argv3, int32_t argv4, uint32_t argv5);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, const char* argv4, uint16_t argv5);
	int32_t RunScriptFunction(int32_t scriptID, const char * functionName, int32_t argv1, const char * argv2, const char * argv3, const char * argv4, const char * argv5);
	// 6
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4, int32_t argv5, const char* argv6);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4, double argv5, const char* argv6);
	int32_t RunScriptFunction(int32_t scriptID, const char * functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4, int32_t argv5, int32_t argv6);
	int32_t RunScriptFunction(int32_t scriptID, const char * functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4, int32_t argv5, int32_t argv6, int32_t argv7);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4, const char* argv5, uint16_t argv6);
	
	// 7
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4, 
		const char* argv5, const char* argv6, char* argv7);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4,
		int32_t argv5, int32_t argv6, char* argv7);

	// 8
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4,
		int32_t argv5, int32_t argv6, const char* argv7, const char* argv8);
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4,
		int32_t argv5, const char* argv6, const char* argv7, const char* argv8);

	// 9
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4,
		int32_t argv5, int32_t argv6, const char* argv7, const char* argv8, const char* argv9);

	// 10
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4,
		int32_t argv5, int32_t argv6, const char* argv7, const char* argv8, const char* argv9, const char* argv10);

	// 11
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4, int32_t argv5, int32_t argv6
		, int32_t argv7, int32_t argv8, int32_t argv9, int32_t argv10, int32_t argv11);

	// 12
	int32_t RunScriptFunction(int32_t scriptID, const char* functionName, int32_t argv1, int32_t argv2, int32_t argv3, int32_t argv4,
		int32_t argv5, int32_t argv6, const char* argv7, const char* argv8, const char* argv9, const char* argv10, const char* argv11,
		const char* argv12);

public:
	int32_t RunScriptFunctionWithRet(int32_t scriptID, const char* functionName, int32_t, int32_t*, int32_t*, int32_t*, int32_t*, int32_t*, int32_t*, int32_t*);
	int32_t RunScriptFunctionWithRet(int32_t scriptID, const char* functionName, uint32_t, int32_t, double*, double*, double*);
	int32_t RunScriptFunctionWithRet(int32_t scriptID, const char* functionName, uint32_t, char*);
	int32_t RunScriptFunctionWithRet(int32_t scriptID, const char* functionName, uint32_t, const char*, int32_t*);
	int32_t RunScriptFunctionWithRet(int32_t scriptID, const char* functionName, int32_t, int32_t, int32_t, int32_t*);
	int32_t RunScriptFunctionWithRet(int32_t scriptID, const char* functionName, int32_t, const char*, char*);

private:
	int32_t runFileFunction(const char* filename, char* function_name, const char* flag, ...);
	std::string runFileFunctionStringRet(const char* filename, char* function_name, const char* flag, ...);

private:
	bool findFunction(const char* functionName);
	bool verifyFunction(int32_t scriptID, const char* functionName);
	void markScriptName(const char* scriptName);
	bool verifyScriptFile(const char* file);

	void scriptError(int32_t errCode);
	void scriptError(int32_t errCode, int32_t retCode);

private:
	void runScriptFunctionStart(int32_t& idx);
	void runScriptFunctionEnd(int32_t idx);

private:
	LuaStack m_stack;
	lua_State *m_state;
	char m_full_function_name[size_256];
	char m_full_filename[size_256];
	char m_temp_str[size_256];

	std::recursive_mutex m_lua_mutex;
	uint32_t m_idx;
	std::atomic_bool m_atomic_bool;

};

using lua_manager_ptr = std::shared_ptr<LuaManager>;

